import Data.Char
import IO
import Data.List
import Array
--DEFINES

data Elemento = IntV Int | FloatV Float | BoolV Bool | StringV String | ClassV Objeto | Void | Null
data Valor = Element Elemento | Array [Valor]
type FoiInicializado = Bool
type Variavel =  (Nome,Valor,IsStatic,IsPrivate,FoiInicializado)
type Flag = Int
type Indice = Int
type PLevel = Int
type Nome = String
type TipoRetorno = String
type NomeDaClasse = String
type TuplaVariavel = (Variavel,Flag)
--type Classe = (Nome,[Variavel],[Method_Dec])
type Classe = Method_Dec
type IsPrivate = Bool
type IsStatic = Bool
type Objeto = (NomeDaClasse,[Variavel])
--Nome, lista de Variaveis e código do método
type Method_Dec = (Nome,[String],[String])
type ListOfBasics = ([ElementoPilha],[Classe])
type ElementoPilha = (Variavel,Flag)
type SentencaParaExecucao = [String]
type Buffer = String

--FUNCOES ADICIONAIS
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


valorParaString :: Valor -> String
valorParaString ( Element (IntV i)) = show i
valorParaString ( Element (StringV i)) = ['"']++i++['"']
valorParaString ( Element (FloatV i)) = show i
valorParaString ( Element (BoolV i)) = show i
valorParaString (Array (a:b)) = (" Array: " ++ (valorArrayParaString (a:b)) )

valorArrayParaString ::  [Valor] -> String
valorArrayParaString [] = ""
valorArrayParaString (a:b) = valorParaString a ++ " " ++ valorArrayParaString b 

boolToString :: Bool -> String
boolToString b
	|b == True = "True"
	|b == False = "False"

stringToBool :: String -> Bool
stringToBool a = if a == "True" then True else False
				
isSuelbiString :: String -> Bool
--isSuelbiString [] = False
isSuelbiString (h:t)
	|h == '"' = isSuelbiString2 t
	|otherwise = False 

isSuelbiString2 :: String -> Bool
isSuelbiString2 (h:[]) = if h == '"' then True else False
isSuelbiString2 (h:t) = if h == '"' then False else isSuelbiString2 t

tirarAspasDeString :: String -> String
tirarAspasDeString (h:t)
	|h == '"' = (tirarAspasDeString2 t)
	|otherwise = (h:t)
 
tirarAspasDeString2 :: String -> String
tirarAspasDeString2 (h:[]) = if h == '"' then [] else [h]
tirarAspasDeString2 (h:t) = h:(tirarAspasDeString2 t)

stringToInt :: String -> Int
stringToInt a = ( read a::Int)					

intToString :: Int -> String
intToString a = show a

stringToFloat :: String -> Float
stringToFloat a = (read a::Float)

floatToString :: Float -> String
floatToString a =  show a

isInt :: String -> Bool
isInt [] = False
isInt (a:b)
	| a == '-' = isInt1 b
	| otherwise = isInt1 (a:b)
	


isInt1 :: String -> Bool
isInt1 [] = False
isInt1 (a:b) 
	| isDigit a = if b /= [] then isInt1 b else True
	| (isDigit a == False) = False

isFloat :: String -> Bool
isFloat [] = False
isFloat (a:b)
	| a == '-' = isFloatA b
	| otherwise = isFloatA (a:b)
	
isFloatA :: String -> Bool
isFloatA [] = False
isFloatA (a:b)
	| a == '.' = False
	| isDigit a = if b /= [] then isFloat3 b else True
	| (isDigit a == False) = False

isFloat3 :: String -> Bool
isFloat3 [] = False
isFloat3 (a:b)
	| a == '.' = isFloat1 b
	| isDigit a = if b /= [] then isFloat3 b else True
	| (isDigit a == False) = False	
	
isFloat1 :: String -> Bool
isFloat1 [] = False
isFloat1 (a:b)
	| isDigit a = if b /= [] then isFloat1 b else True
	| (isDigit a == False) = False
	| a == '.' = False

--ANALISADOR SINTATICO
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--Retorna a cabeça da lista de Strings
first :: [String] -> String
first [] = ""
first (h:t) = h

--Retorna o rabo da lista de Strings
updt :: [String] -> [String]
updt [] = []
updt (h:t) = t

--method_dec :: [String] -> (Bool,[String])
--method_dec [] = (False,[])
--method_dec lexems = let (

class_dec :: [String] -> (Bool,[String])
class_dec a = (True,a)

module_dec :: [String] -> (Bool,[String])
module_dec a = (True,a)								

for_cond :: [String] -> (Bool,[String])
for_cond a = (True,a)
					
							
op :: [String] -> (Bool,[String])
op [] = (False,[])
op (a:[]) = if (a == "**" || 
				a ==  "-" ||
				a ==  "+" ||
				a ==  "*" ||
				a ==  "/" || 
				a ==  "%" ||
				a ==  ">" ||
				a == ">=" || 
				a ==  "<" || 
				a == "<=" || 
				a == "==" || 
				a == "&&" || 
				a == "||" || 
				a == "!=") then (True,[])
					else (False,a:[])
op (a:b)  = if (a == "**" || 
				a ==  "-" || 
				a ==  "+" || 
				a ==  "*" || 
				a ==  "/" || 
				a ==  "%" || 
				a ==  ">" || 
				a == ">=" || 
				a ==  "<" || 
				a == "<=" || 
				a == "==" || 
				a == "&&" || 
				a == "||" || 
				a == "!=") then (True,b)
			else (False, a:b)

calcularParentesesFechando :: [String] -> Int -> ([String],Int,Bool)
calcularParentesesFechando [] n = ([],n,False)
calcularParentesesFechando (a:b) n = if a == "(" then ((a:b),n,False)
									else if a == ")" then (calcularParentesesFechando b (n - 1))									
									else ((a:b),n,True)
	
calcularParentesesAbrindo :: [String] -> Int -> ([String],Int,Bool)
calcularParentesesAbrindo (a:b) n = if a == "(" then (calcularParentesesAbrindo b (n + 1))
									else if a == ")" then ((a:b),n,False)
									else ((a:b),n,True) 
	
isCaractere :: Char -> Bool
isCaractere a = if (ord a >= 48 && ord a <= 90) || (ord a >= 97 && ord a <= 122) then True 	
				else False	
															
executarSentenca :: [(String,Indice,PLevel)] -> [(Valor,[Int])] -> ListOfBasics -> (Bool,Valor)
executarSentenca [] operands loB = let (a,b):c = operands in (True,a)
executarSentenca ((a,b,c):d) operands loB = 	let ((opS1,i1),operands2,(str,ndc)) = procurarPrimeiroOperando (a,b,c) operands (Element Null,[b]) in
													let ((opS2,i2),operands3,(str2,ndc2)) = procurarSegundoOperando  (a,b,c) operands2 (str,ndc) in
														let (status,valor) = executarUmaOperacao opS1 opS2 a loB in
														if status == False then (False,Element (BoolV False))
														else (executarSentenca d (operands3++[(valor,ndc2)]) loB)
														

executarAttrib :: String -> Valor -> ListOfBasics -> [Int] -> (Bool,ListOfBasics)
executarAttrib nome valor loB indexes =	let (status,var) = (verificarVariavel nome loB False)
								in if status == True then
										let (a,b,c,d,e) = var in
										let (status2,b2) = executarAttrib2 b valor indexes in
										if status2 == False then (False,loB) 
										else (True,(substituirVariavel (a,b2,c,d,True) loB))									
								   else (False,loB)

execTeste::(Bool,String)
execTeste = let (status,val) =   executarAttrib2 (Array [(Array [Element (IntV 10),Element (IntV 15)]),(Array [Element (IntV 20),Element (IntV 30)])]) (Element (IntV 100	)) [2,2] in
			(status,valorParaString val)
								   								   
								   
						   
executarAttrib2 :: Valor -> Valor -> [Int] -> (Bool,Valor)	
executarAttrib2 ( Element (IntV recebe)) y (h:t) = (False,y)
executarAttrib2 ( Element (FloatV recebe)) y (h:t) = (False,y)
executarAttrib2 ( Element (StringV recebe)) y (h:t) = (False,y)
executarAttrib2 ( Element (BoolV recebe)) y (h:t) = (False,y)
executarAttrib2 ( Element (FloatV recebe)) y (h:t) = (False,y)
executarAttrib2 x y [] = (True,y)
executarAttrib2 (Array (a:b)) x (h:t) = let (status,valor) = getElementoDoArray (a:b) h in 
														if status == True then
															let (status2,valor2) = (executarAttrib2 valor x t) in
																if status2 == True then
																	let (status3,valor3) = substituirElementoDoArray (a:b) h valor2 in
																		if status3 == True then (True,Array (valor3))
																	else (False,Element (IntV 40))	
																else (False,valor2)
														else (False,valor)
executarAttrib2 (Array (a:b)) x (h:[]) = let (status,valor) = substituirElementoDoArray (a:b) h x in
										if status == True then (True,Array (valor)) else (False,Array (valor))
								
	
verificarArraysDe2Variaveis :: Valor -> Valor -> Bool
verificarArraysDe2Variaveis (Array (a:b)) (Array (c:d)) = verificarArraysDe2Variaveis a c 	
verificarArraysDe2Variaveis ( Element (IntV recebe)) (Element (IntV atrib)) = True
verificarArraysDe2Variaveis ( Element (FloatV recebe)) (Element (FloatV atrib)) = True
verificarArraysDe2Variaveis ( Element (StringV recebe)) (Element (StringV atrib)) = True
verificarArraysDe2Variaveis ( Element (BoolV recebe)) (Element (BoolV atrib)) = True
verificarArraysDe2Variaveis a b = False
	

executarUmaOperacao :: Valor -> Valor -> String -> ListOfBasics -> (Bool,Valor)
executarUmaOperacao s1 s2 op lob =  let (status,valor) = realizarOperacao s1 s2 op
									in if status == True then (True,valor) else
									(False,s1)
												
realizarOperacao :: Valor -> Valor -> String -> (Bool,Valor)
realizarOperacao ( Element (IntV i)) ( Element (IntV j)) op
	|op == "**" = (True,( Element (IntV (i ^ j))))
	|op == "-"  = (True,( Element (IntV (i - j))))
	|op == "+"  = (True,( Element (IntV (i + j))))
	|op == "*"  = (True,( Element (IntV (i * j))))
	|op == "/"  = (True,( Element (IntV (div i j))))
	|op == "%"  = (True,( Element (IntV (mod i j))))
	|op == ">"  = (True,( Element (BoolV (i > j))))
	|op == ">=" = (True,( Element (BoolV (i >= j))))
	|op == "<"  = (True,( Element (BoolV (i < j))))
	|op == "<=" = (True,( Element (BoolV (i <= j))))
	|op == "==" = (True,( Element (BoolV (i == j))))
	|op == "&&" = (False,( Element (BoolV False)))
	|op == "||" = (False,( Element (BoolV False)))
	|op == "!=" = (True,( Element (BoolV (i /= j))))
	|otherwise = (False,( Element (Null)))
realizarOperacao ( Element (FloatV i)) (Element (FloatV j)) op
	|op == "**" = (True,( Element (FloatV (i ** j))))
	|op == "-"  = (True,( Element (FloatV (i - j))))
	|op == "+"  = (True,( Element (FloatV (i + j))))
	|op == "*"  = (True,( Element (FloatV (i * j))))
	|op == "/"  = (True,( Element (FloatV (i / j))))
	|op == ">"  = (True,( Element (BoolV (i > j))))
	|op == ">=" = (True,( Element (BoolV (i >= j))))
	|op == "<"  = (True,( Element (BoolV (i < j))))
	|op == "<=" = (True,( Element (BoolV (i <= j))))
	|op == "==" = (True,( Element (BoolV (i == j))))
	|op == "&&" = (False,( Element (BoolV False)))
	|op == "||" = (False,( Element (BoolV False)))
	|op == "!=" = (True,( Element (BoolV (i /= j))))
	|otherwise = (False,( Element (Null)))
realizarOperacao ( Element (BoolV i)) (Element (BoolV j)) op
	|op == "==" = (True,( Element (BoolV (i == j))))
	|op == "&&" = (True,( Element (BoolV False)))
	|op == "||" = (True,( Element (BoolV False)))
	|op == "!=" = (True,( Element (BoolV (i /= j))))
	|otherwise = (False,( Element (BoolV False)))
realizarOperacao ( Element (StringV i)) (Element (StringV j)) op
	|op == "+"  = (True,( Element (StringV (i++j))))
	|op == ">"  = (True,( Element (BoolV (i > j))))
	|op == ">=" = (True,( Element (BoolV (i >= j))))
	|op == "<"  = (True,( Element (BoolV (i < j))))
	|op == "<=" = (True,( Element (BoolV (i <= j))))
	|op == "==" = (True,( Element (BoolV (i == j))))
	|op == "!=" = (True,( Element (BoolV (i /= j))))
realizarOperacao ( Element (FloatV i)) (Element (IntV j)) op
	|op == "**" = (True,( Element (FloatV (i ** (fromIntegral j)))))
	|op == "-"  = (True,( Element (FloatV (i - (fromIntegral j)))))
	|op == "+"  = (True,( Element (FloatV (i + (fromIntegral j)))))
	|op == "*"  = (True,( Element (FloatV (i * (fromIntegral j)))))
	|op == "/"  = (True,( Element (FloatV (i / (fromIntegral j)))))
	|op == ">"  = (True,( Element (BoolV (i > (fromIntegral j)))))
	|op == ">=" = (True,( Element (BoolV (i >= (fromIntegral j)))))
	|op == "<"  = (True,( Element (BoolV (i < (fromIntegral j)))))
	|op == "<=" = (True,( Element (BoolV (i <= (fromIntegral j)))))
	|op == "==" = (True,( Element (BoolV (i == (fromIntegral j)))))
	|op == "&&" = (False,( Element (BoolV False)))
	|op == "||" = (False,( Element (BoolV False)))
	|op == "!=" = (True,( Element (BoolV (i /= (fromIntegral j)))))
	|otherwise = (False,( Element (Null)))
realizarOperacao ( Element (IntV i)) (Element (FloatV j)) op
	|op == "**" = (True,( Element (FloatV ((fromIntegral i) ** j))))
	|op == "-"  = (True,( Element (FloatV ((fromIntegral i) - j))))
	|op == "+"  = (True,( Element (FloatV ((fromIntegral i) + j))))
	|op == "*"  = (True,( Element (FloatV ((fromIntegral i) * j))))
	|op == "/"  = (True,( Element (FloatV ((fromIntegral i) / j))))
	|op == ">"  = (True,( Element (BoolV ((fromIntegral i) > j))))
	|op == ">=" = (True,( Element (BoolV ((fromIntegral i) >= j))))
	|op == "<"  = (True,( Element (BoolV ((fromIntegral i) < j))))
	|op == "<=" = (True,( Element (BoolV ((fromIntegral i) <= j))))
	|op == "==" = (True,( Element (BoolV ((fromIntegral i) == j))))
	|op == "&&" = (False,( Element (BoolV False)))
	|op == "||" = (False,( Element (BoolV False)))
	|op == "!=" = (True,( Element (BoolV ((fromIntegral i) /= j))))
	|otherwise = (False,( Element (Null)))
realizarOperacao a b op = (False,( Element (Null)))

-- O Terceiro dado armazena as posições do dado encontrado
procurarPrimeiroOperando :: (String,Indice,PLevel) -> [(Valor,[Int])] -> (Valor,[Int]) -> ((Valor,[Int]),[(Valor,[Int])],(Valor,[Int]))
procurarPrimeiroOperando (a,b,c) [] (h,i) = ((Element (Null),[]),[(Element Null,[])],(Element (Null),[]))
procurarPrimeiroOperando (a,b,c) ((e,f):g) (h,i)
	|verificarIndiceMenorOperando b f == True = ((e,f),g,(h,f++i))
	|otherwise =  let (pri,sec,thi) = (procurarPrimeiroOperando (a,b,c) g (h,i)) in (pri,(e,f):sec,thi)

	
--	O Terceiro dado armazena as posições do dado encontrado
procurarSegundoOperando :: (String,Indice,PLevel) -> [(Valor,[Int])] -> (Valor,[Int]) -> ((Valor,[Int]),[(Valor,[Int])],(Valor,[Int]))
procurarSegundoOperando (a,b,c) [] (h,i) = ((Element (Null),[]),[],(Element (Null),[]))
procurarSegundoOperando (a,b,c) ((e,f):g) (h,i)	
	|verificarIndiceMaiorOperando b f == True = ((e,f),g,(h,f++i))
	|otherwise =  let (pri,sec,thi) = (procurarSegundoOperando (a,b,c) g (h,i)) in (pri,(e,f):sec,thi)
												
												
verificarIndiceMenorOperando :: Indice -> [Int] -> Bool
verificarIndiceMenorOperando n (a:b)
	|n == (a + 1) = True 
	|b == [] = False
	|otherwise = verificarIndiceMenorOperando n b

verificarIndiceMaiorOperando :: Indice -> [Int] -> Bool
verificarIndiceMaiorOperando n (a:b)
	|n == (a - 1) = True 
	|b == [] = False
	|otherwise = verificarIndiceMaiorOperando n b
											
--qsort1 :: Ord a => [a] -> [a]
--qsort1 []     = []
--qsort1 (p:xs) = qsort1 lesser ++ [p] ++ qsort1 greater
--    where
--       lesser  = [ y | y <- xs, y < p ]
--        greater = [ y | y <- xs, y >= p ]
	
qsort1 :: [(String,Indice,PLevel)] -> [(String,Indice,PLevel)]
qsort1 []     = []
qsort1 ((a,b,c):xs) = qsort1 lesser ++ [(a,b,c)] ++ qsort1 greater
    where
        lesser  = [ (d,e,f) | (d,e,f) <- xs, menor_que_op False (d,e,f) (a,b,c)  ]
        greater = [ (d,e,f) | (d,e,f) <- xs, (e >= b) || menor_que_op True (a,b,c) (d,e,f) ]	
	
op_prio :: String -> Int
op_prio m
	|m == "**" = 5
	|m == "*" || m == "/" || m == "%" = 4
	|m == "-" || m == "+" = 3
	|m == ">" || m == ">=" || m == "<" || m == "<=" || m == "==" || m == "!=" = 2
	|m == "&&" || m == "||" = 1
	|otherwise = 0
	
menor_que_op :: Bool -> (String,Indice,PLevel) -> (String,Indice,PLevel) -> Bool
menor_que_op t (a,f,b) (d,g,e)
	|t == False  =  if b < e then True
					else if b > e then False
					else if op_prio a < op_prio d then True
					else False
	|otherwise  = 	if b < e then True
					else if b > e then False
					else if op_prio a <= op_prio d then True
					else False
																																	
stringDeTipe:: Int -> String
stringDeTipe tipe
	|tipe == 1 = ";"
	|tipe == 2 = "then"
	|otherwise = "do"
	
obterValorDeElemento :: [String] -> ListOfBasics -> Buffer -> (Bool,Valor,[String],ListOfBasics,Buffer)
obterValorDeElemento strings lista buffer =	let (status,valor) = obterValorDeLiteral (first strings) in
												if status == True then (True,valor,(updt strings),lista,buffer)
												else let (status2,indexes,strings2) = isArrayVar strings in
													let (status3,valor3) = obterValorDeVariavel (first strings) lista in
													if status3 == True then 
														if status2 == True then
															let (status4,valor4) = getValor valor3 indexes in
																if status4 == True then (True,valor4,strings2,lista,buffer) 
																else (False,Element Null,strings,lista,buffer)
														else let (status5,valor5) = getValor valor3 [] in
															if status5 == True then (True,valor5,(updt strings),lista,buffer) 
															else (False,Element Null,strings,lista,buffer) 
													else let (statusM,listaM,valorM,stringsM,bufferM) = isMetodo strings lista buffer in 
						 								(statusM,valorM,stringsM,listaM,bufferM)
								
verificarOperacao :: Int -> [String] -> ListOfBasics -> [(String,Indice,PLevel)] -> [(Valor,[Int])] -> Int -> Int -> Buffer -> (Bool,[String],Valor,Buffer)
verificarOperacao tipe strings lista operadores operandos n index buffer =
				let (status,valor,strings2,lista2,buffer2) = obterValorDeElemento strings lista buffer in
					if status == False then (False,strings,Element Null,buffer2)
					else let(parStrings,n2,status2) = (calcularParentesesFechando strings2 n) in
						if status2 == False then (False,strings,(Element Null),buffer2) 
						else let (status3,newStrings2) = op parStrings in
							if status3 == True then let (parStrings2,n3,status4) = calcularParentesesAbrindo newStrings2 n2 in
								if status4 == False then (False,strings,(Element Null),buffer2)
								else (verificarOperacao tipe parStrings2 lista2 (operadores++[((first parStrings),index+1,n3)]) (operandos++[((valor),[index])]) n3 (index + 2) ) buffer2
							else if first parStrings == (stringDeTipe tipe) then
								if n2 /= 0 then (False,strings,(Element Null),buffer2)
								else let operadores2 = qsort1 operadores in
									let (status5,valor2) = executarSentenca operadores2 (operandos++[((valor),[index])]) lista2 in 
									if status5 == False then (False,[],(Element Null),buffer2)
									else (True,(updt parStrings),valor2,buffer2)
							else (False,strings,(Element Null),buffer2)
							
isNomeOuLiteral::[String] -> (Bool,[String])
isNomeOuLiteral [] = (False,[])
isNomeOuLiteral strings = let (status,strings2) = nome strings in
							if status == True then (True,strings2)
							else let (status,valor) = obterValorDeLiteral (first strings) in
							if status == True then (True, updt strings)
							else (False,strings)
																																	
						
isArrayOrNome::[String] -> (Bool,[Int],[String])
isArrayOrNome strings = let (status,indexes,strings2) = isArrayVar strings in
							if status == True then (True,indexes,strings2)
							else let (status2,strings3) = nome strings in
								if status2 == True then (True,[],strings3) else
								(False,[],strings)
					
var_manip :: [String] -> ListOfBasics -> Buffer -> (Bool,[String],ListOfBasics,Buffer)
var_manip [] lista buffer = (False,[],lista,buffer)
var_manip (palavra:[]) lista buffer = (False,[palavra],lista,buffer)
var_manip strings lista buffer = let (status , strings2 , valor, buffer2 , loB ) = (verificarMetodo strings lista buffer) in
									if status == False then 					
										let (statusAr,dim,stringsAr) = isTypeArray strings in
											if statusAr == True then let (statusAr2,stringsAr2) = nome stringsAr in
												if statusAr2 == False then (False,strings,lista,buffer2)
												else if (first stringsAr2) == ";" then let (statusAr3,listaAr3) = declaraNovaVariavel lista (first strings) (first stringsAr) dim in
													if statusAr3 == True then (True,updt stringsAr2,listaAr3,buffer2)
													else (False,strings,lista,buffer2)
												else (False,strings,lista,buffer2)				
											else let ( status2 ,dim, stringsAlfa ) = isArrayOrNome strings in
												if status2 == False then (False,strings,lista,buffer2)
												else if first stringsAlfa == "=" then let (status3,strings3,valor2,buffer3) = verificarOperacao 1 (updt stringsAlfa) lista [] [] 0 0 buffer2 in
														if status3 == False then (False,strings,lista,buffer3)
														else let (status4,lista2) = (executarAttrib (first strings) valor2 lista dim) in
															if status4 == False then (False,strings,lista,buffer3) 
															else (True,strings3,lista2,buffer3)							
												else let (status5,stringsBeta) = nome (stringsAlfa) in
													if status5 == True then
														if first stringsBeta == ";" then
															let (status6,lista3) = (declaraNovaVariavel lista (first strings) (first stringsAlfa)) 0 in (status6,updt stringsBeta, lista3,buffer2)
														else (False,strings,lista,buffer2)
													else (False,strings,lista,buffer2)												
									else if (isNull valor) && (first strings2) == ";" then (True,(updt strings2),loB,buffer2)
									else (False,strings,lista,buffer2)	

									
									
							
isNull :: Valor -> Bool
isNull (Element Null) = True
isNull a = False							
							  
numero :: [String] -> (Bool,[String])
numero [] = (False,[])
numero (a:[]) = let (car:str) = a in
				if (isNumber car) then
					if (numero1 str False) then
					(True,[]) else (False,(a:[]))
				else (False,(a:[]))
numero (a:b) = let (car:str) = a in
				if (isNumber car) then
					if (numero1 str False) then
					(True,b) else (False,(a:b))
				else (False,(a:b))
				
				
				
numero1 :: String -> Bool -> Bool
numero1 [] tem_ponto = True
numero1 (digito:[]) tem_ponto = isNumber digito
numero1 (digito:sequencia) tem_ponto = if (tem_ponto == False && digito == '.') then numero1 sequencia True
									   else if (isNumber digito) then numero1 sequencia tem_ponto
									   else False

									   
isAlfabeticCharacter :: Char -> Bool
isAlfabeticCharacter a = if ord a >= 65 && ord a <= 90 || ord a >= 97 && ord a <= 122 then True else False

				  
nome :: [String] -> (Bool,[String])
nome [] = (False,[])
nome (a:[]) = let (car:str) = a in
			   if isAlfabeticCharacter car then	
			  (True,[]) else (False, a:[])
nome (a:b) = let (car:str) = a in
				if isAlfabeticCharacter car && nome1 str then
			  (True, b) else (False,(a:b))
			  
			  
nome1 :: String -> (Bool)
nome1 [] = True
nome1 (a:[]) = isCaractere a
nome1(a:b) = isCaractere a && nome1 b

program::[String] -> ListOfBasics -> Buffer -> (Bool,Buffer)
program [] lista buffer = (True,buffer)
program lexems lista buffer = let (status,lexems2,lista2,buffer2) = (stmt lexems lista buffer) in
								if status == False then (False,buffer)
								else program lexems2 lista2 buffer2

				 
stmt :: [String] -> ListOfBasics -> Buffer -> (Bool,[String],ListOfBasics,Buffer)
stmt [] lista buffer = (True,[],lista,buffer)
stmt lexems lista buffer = let bkup_lexems = lexems in
				if first lexems == "def" then 
					let (status,strings2,lista2) = method_dec (updt lexems) lista in
						if status == False then (False,[],([],[]),buffer)
						else (True,strings2,lista2,buffer)
--				else if first lexems == "class" then
--					let (status,lexem) = class_dec (updt lexems) in 
--						if status == False then (False,bkup_lexems)
--						else (True,lexems)				
--				else if first lexems == "module" then
--							let (status,lexem) = module_dec (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
--				else if first lexems == "require" then
--							let (status,lexem) = nome (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
				else if first lexems == "if" then
							let (status,lexems3,lista3,buffer3) = if_cond (updt lexems) lista buffer False in 
								if status == False then (False,bkup_lexems,lista,buffer)
								else (True,lexems3,lista3,buffer3)
				else if first lexems == "while" then
							let (status4,lexems4,lista4,buffer4) = while_cond (updt lexems) lista buffer in 
								if status4 == False then (False,bkup_lexems,lista,"Falhou no while do stmt")
								else (True,lexems4,lista4,buffer4)
--				else if first lexems == "for" then
--							let (status,lexem) = for_cond (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
				else
				let (status,lexems2,lista2,buffer2) = (var_manip lexems lista buffer) in 
								if status == False then (False,bkup_lexems,lista,buffer)
								else (True,lexems2,lista2,buffer2)

--ANALISADOR LEXICO
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--TESTES2

imprimirElementos::IO ()
imprimirElementos = let (status,lexems2,(lista2,classes),buffer2) = (var_manip ["int","a",";"] ([],[]) "") in
							(imprimirElementosDaPilha lista2)
						


imprimirElementosDaPilha:: [ElementoPilha] -> IO()
imprimirElementosDaPilha [] = putStr ""
imprimirElementosDaPilha (((a,b,c,d,e),f):pilha) =  do
													putStr (a ++ (valorParaString b) ++ boolToString c ++ boolToString d ++ boolToString e)
													imprimirElementosDaPilha pilha
	
main fn = 
		do 	x <- openFile fn ReadMode
			y <- hGetContents x
			--let (h:t) = (analisador_lexico (words y) 2) in putStr(show (h:t))
			let (status,buffer) = (interpretador (words y) ) in --putStr(show ((boolToString status):(h:t)))
				if status == False then putStr ("Falhou:" ++ buffer )
				else putStr ("Interpretado com Sucesso. Inicializando:\n" ++ buffer)
			
main fn = 
		do 	x <- openFile fn ReadMode
			y <- hGetContents x
			let (h:t) = (analisador_lexico_total (words y)) in putStr(show (h:t))

			
interpretador :: [String] -> (Bool,String)
interpretador [] = (False,"Nao ha nada para interpretar")
interpretador lista = let lex = (analisador_lexico lista 2) in
									let (status,buffer) = (program lex ([],[]) [])
									in (status,buffer)	

--analisador_lexico :: [String] -> Int -> [String]
--analisador_lexico [] n = []
--analisador_lexico (head:tale) n = let (a,b) = (analisador_string head [] n)	in a++(analisador_lexico tale b)

analisador_lexico :: [String] -> Int -> [String]
analisador_lexico [] n = []
analisador_lexico (head:tale) n = let (a,b) = (analisador_string head [] n)	in a++(analisador_lexico tale b)

analisador_lexico_total::[String] -> [String]
analisador_lexico_total strings = let strings1 = analisador_lexico strings 2 in
									let strings2 = analisadorMinus strings1 in
										strings2


analisadorMinus :: [String] -> [String]
analisadorMinus [] = []
analisadorMinus (a:b)
	|a == "(" = let minus = first b in 
					if minus == "-" then
						let c = (updt b) in
							let (status,strings) = numero c in
							if status == True then
								([a] ++ [minus ++ (first c) ] ++ (analisadorMinus strings))
							else a:(analisadorMinus b)
					else a:(analisadorMinus b)
				


	
isDoubleOperator :: Char -> String -> (Bool,Char)
isDoubleOperator m [] = (False, ' ')
isDoubleOperator m string = let (h:t) = string in
								if m == '*' && h == '*' then (True,h)
								else if (m == '>' || m == '<' || m == '=' || m == '!' ) && h == '=' then (True,h)
								else if m == '&' && h == '&' then (True,h)
								else if m == '|' && h == '|' then (True,h)
								else if m == '<' && h == '<' then (True,h)
								else (False,m)

isOperator :: String -> Bool
isOperator [] = False
isOperator a = if (a == "**" ||
				a == "="  ||
				a ==  "-" ||
				a ==  "+" ||
				a ==  "*" ||
				a ==  "/" || 
				a ==  "%" ||
				a ==  ">" ||
				a == ">=" || 
				a ==  "<" || 
				a == "<=" || 
				a == "==" || 
				a == "&&" || 
				a == "||" || 
				a == "!=" ||
				a == "("  ||
				a == ")"  ||
				a == "<<" ||
				a == ","  ||
				a == "["  ||
				a == "]"  ||
				a == "("  ||
				a == ")"  ||
				a == ","  ||
				a == ";"  )				then True
					else False

nextElementIs :: Char -> String -> Bool
nextElementIs a [] = False
nextElementIs car string = let (h:t) = string in if h == car then True else False

					
--n = 0 : modo comentario
--n = 2 : modo normal
analisador_string :: String -> String -> Int -> ([String],Int)
analisador_string [] [] n
	|n == 0 || n == 1 = ([],1)
	|otherwise = ([],2)	
analisador_string [] b n
	|n == 0 || n == 1 = ([b],1)
	|otherwise = ([b],2)	
analisador_string (a:b) c n
	| n == 0 && a == '*' = if (nextElementIs '/' b) then let (h:t) = b in
								analisador_string t [] 2
							else analisador_string b [] 0
	| n == 0 && a /= '*' = analisador_string b [] 0
	| n == 2 && a == '/' =  if (nextElementIs '*' b) then let (h:t) = b in
								let (string,int) = analisador_string t [] 0 in
								if c == [] then (string,int)
								else (c:string,int)
							else let (string,int) = analisador_string b [] 2 in
							if c == [] then ([[a]]++string,int)
							else (c:[[a]]++string,int)
	| n == 2 && a == '*' =  if (nextElementIs '*' b) then 
								let (h:t) = b in
									let (string,int) = analisador_string t [] 2 in
										if c == [] then (["**"]++string,int)
										else (c:["**"]++string,int)
							else let (string,int) = analisador_string b [] 2 in
								if c == [] then ([[a]]++string,int)
									else (c:[[a]]++string,int)	
	| n == 2 && (isOperator [a] == False)  = analisador_string b (c++[a]) 2						
	| (n == 2) = let (tipe,op) = (isDoubleOperator a b) in
								if op == ' ' then
									if c == [] then ([[a]],2)
											else (c:[[a]],2)
								else if tipe == True then
									let (h:t) = b in
										let (string,int) = analisador_string t [] 2 in
											if c == [] then ([[a]++[op]]++string,int)
											else (c:[[a]++[op]]++string,int)
								else let (string,int) = analisador_string b [] 2 in
									if c == [] then ([[a]]++string,int)
										else (c:[[a]]++string,int)

--FUNCOES PILHA_EXECUCAO E CLASSE
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
firstC :: [Classe] -> Classe
firstC (h:t) = h

lastC :: [Classe] -> [Classe]
lastC [] = []
lastC (h:t) = t

firstG :: [ElementoPilha] -> ElementoPilha
firstG (h:t) = h

lastG :: [ElementoPilha] -> [ElementoPilha]
lastG [] = []
lastG (h:t) = t

getElementoDaPilha :: [ElementoPilha] -> String -> (Bool,Variavel)
getElementoDaPilha ((elemento,flag):t) nome
	|flag == 3 = (False,("fail",Element Null, False, False, False))
	|flag == 2 = getElementoDaPilha t nome
	|flag == 1 = let (a,b,c,d,e) = elemento in
				if a == nome then (True,elemento)
				else getElementoDaPilha t nome
				
--getClasse :: [Classe] -> String -> (Bool,Classe)
--getClasse [] nome = (False,[],[],[])
--getClasse ((nomeDaClasse,b,c):t) nome
--	|nomeDaClasse == nome = (True,(nomeDaClasse,b,c))
--	|otherwise = getClasse t nome  				


--type Classe = (Nome,[Variavel],[Method_Dec])

--OBS: Se Band = 1, então é variável, se Band = 2, então é flag, mas pode acessar o que estiver abaixo
-- e se Band = 3, é Flag mas NãO pode acessar o que estiver abaixo da pilha de execução

declaraNovaVariavel :: ListOfBasics -> String -> String -> Int -> (Bool,ListOfBasics)
declaraNovaVariavel (pilha,classes) tipo nome n
	|n == 0 = 	if (tipo == [] || nome == []) then (False,([],[]))
				else if (ehTipoBasico tipo) then
					if (not (nomeDeVarJaExiste pilha nome)) then 
						(True,((adicionarNovaVariavel pilha tipo nome),classes))
					else (False,([],[]))															
				else (False,([],[]))
	| n > 0 = 	if (tipo == [] || nome == []) then (False,([],[]))
				else if (ehTipoBasico tipo) then
					if (not (nomeDeVarJaExiste pilha nome)) then
						(True,((adicionarNovoArray pilha tipo nome (converterDimensaoEmArray n)),classes))	
					else (False,([],[]))															
				else (False,([],[]))
	



obterValorDeVariavel :: String -> ListOfBasics -> (Bool,Valor)
obterValorDeVariavel string lista = let (status,(a,valor,c,d,e)) = verificarVariavel string lista False
									in if status == True then (True,valor)
									else (False,valor)



-- O BOOL deve sempre ser inicializado com False
verificarVariavel :: String -> ListOfBasics -> Bool -> (Bool,Variavel)
verificarVariavel nome ([],classes) st = (False,(nome,Element (Null),False,False,False))
verificarVariavel nome ((var,flag):pilha,classes) st
	|flag == 2 = verificarVariavel nome (pilha,classes) st
	|flag == 3 = verificarVariavel nome (pilha,classes) True
	|flag == 1 && st == False = let (a,b,c,d,e) = var in
							if a == nome then (True,var)
							else verificarVariavel nome (pilha,classes) st
	|flag == 1 && st == True = let (a,b,c,d,e) = var in
							if a == nome && c == True then (True,var)
							else verificarVariavel nome (pilha,classes) st

substituirVariavel :: Variavel -> ListOfBasics -> ListOfBasics
substituirVariavel (a,b,c,d,e) ((((f,g,h,i,j),flag):pilha),classes)
	|flag == 2 || flag == 3 = let (l,m) = substituirVariavel (a,b,c,d,e) (pilha,classes) in (((f,g,h,i,j),flag):l,m)
	|a == f = (((a,b,c,d,e),1):pilha,classes)
	|otherwise = let (l,m) = substituirVariavel(a,b,c,d,e) (pilha,classes) in (((f,g,h,i,j),flag):l,m)							
	
										
adicionarNovaVariavel :: [ElementoPilha] -> String -> String -> [ElementoPilha]
adicionarNovaVariavel [] tipo nome = if tipo == "String" then
											((nome, Element (StringV ""),False,False,False),1):[]
										else if tipo == "bool" then
											((nome,Element (BoolV False),False,False,False),1):[]
										else if tipo == "float" then
											((nome,Element (FloatV 0),False,False,False),1):[]
										else if tipo == "int" then
											((nome,Element (IntV 0),False,False,False),1):[]
										else ((nome,(Element Null ),False,False,False),1):[]
adicionarNovaVariavel pilha tipo nome = if tipo == "String" then
											((nome, Element (StringV ""),False,False,False),1):pilha
										else if tipo == "bool" then
											((nome,Element (BoolV False),False,False,False),1):pilha
										else if tipo == "float" then
											((nome,Element (FloatV 0),False,False,False),1):pilha
										else if tipo == "int" then
											((nome,Element (IntV 0),False,False,False),1):pilha
										else ((nome,(Element Null ),False,False,False),1):pilha
		
										
										
										
--existeTipoDefinido :: [Classe] -> String -> Bool
--existeTipoDefinido [] tipo = False
--existeTipoDefinido classes tipo = let (a,b,c) = firstC classes in
--										if a == tipo then True else
--										existeTipoDefinido (lastC classes) tipo
										
										
										
ehTipoBasico :: String -> Bool
ehTipoBasico tipo = if tipo == "String" || tipo == "float" || tipo == "int" || tipo == "bool" then True else False									

nomeDeVarJaExiste :: [ElementoPilha] -> String -> Bool
nomeDeVarJaExiste [] nome = if nome /= [] then False else True
nomeDeVarJaExiste pilha nome = let (var,flag) = firstG pilha in
								if flag == 3 then False
								else if flag == 2 then nomeDeVarJaExiste (lastG pilha) nome
								else let (a,b,c,d,e) = var in if
								a == nome then True
								else nomeDeVarJaExiste (lastG pilha) nome			
	
	
--FUNCOES CLASSES
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--verificarParametros(first strings,updt strings2)

verificarMetodo :: [String] -> ListOfBasics -> Buffer -> (Bool,[String],Valor,Buffer,ListOfBasics)
verificarMetodo [] loB buffer = (False,[],Element Null,buffer,loB)
verificarMetodo strings loB buffer = let (status,strings2) = nome strings in
									if status == False then (False,strings,Element Null,buffer,loB)
									else if (first strings2) /= "(" then (False,strings,Element Null,buffer,loB)
									else if (first strings) == "putLine" || (first strings) == "puts" then
											let strings3 = (updt strings2) in
												let (status11,valor3,strings4,lista2,bufferM) = obterValorDeElemento strings3 loB buffer in
													if ((first strings4) /= ")") then (False,strings,(Element Null),bufferM,lista2)
													else if status11 == True then let buffer2 = (imprimirDadoNoBuffer valor3 bufferM True) in
																(True,updt strings4,(Element Null),buffer2,lista2)
															else (False,strings,(Element Null),buffer,lista2)																	
										else if (first strings) == "New" then
											let strings3 = (updt strings2) in
												let (status2,(a,val,b,c,d)) = verificarVariavel (first strings3) loB False in
													if status2 == True then
														let strings4 = (updt strings3) in
															if first strings4 == "," then 
																let strings5 = updt strings4 in
																	if isTypeString (first strings5) then
																		let (status3,indexes,strings6) = localizarIndices (updt strings5) [] in
																			if status3 == True then
																				let lista = substituirVariavel (a,(criarNovoArray (first strings5) indexes),b,c,True) loB in
																					(True,strings6,(Element Null),buffer,lista)
																			else (False,strings,(Element Null),buffer,loB)		
																	else (False,strings,(Element Null),buffer,loB)				
															else (False,strings,(Element Null),buffer,loB)						
													else (False,strings,(Element Null),buffer,loB)								
										else (False,strings,(Element Null),buffer,loB)
										
verificarMetodo1 :: [String] -> ListOfBasics -> Buffer -> (Bool,[String],Int,Buffer,[Int])
verificarMetodo1 [] loB buffer = (False,[],0,buffer,[])
verificarMetodo1 strings loB buffer = let (status,strings2) = nome strings in
									if status == False then (False,strings,1,buffer,[])
									else if (first strings2) /= "(" then (False,strings,2,buffer,[])
									else if (first strings) == "putLine" || (first strings) == "puts" then
											let strings3 = (updt strings2) in
												let (status11,valor3,strings4,lista2,bufferM) = obterValorDeElemento strings3 loB buffer in
													if ((first strings4) /= ")") then (False,strings,3,bufferM,[])
													else if status11 == True then let buffer2 = (imprimirDadoNoBuffer valor3 bufferM True) in
																(True,updt strings4,4,buffer2,[])
															else (False,strings,5,buffer,[])																	
										else if (first strings) == "New" then
											let strings3 = (updt strings2) in
												let (status2,(a,val,b,c,d)) = verificarVariavel (first strings3) loB False in
													if status2 == True then
														let strings4 = (updt strings3) in
															if first strings4 == "," then 
																let strings5 = updt strings4 in
																	if isTypeString (first strings5) then
																		let (status3,indexes,strings6) = localizarIndices (updt strings5) [] in
																			if status3 == True then
																				let lista = substituirVariavel (a,(criarNovoArray (first strings5) indexes),b,c,True) loB in
																					(True,strings6,6,(first strings5) ++ " EEE " ++ a,indexes)
																			else (False,(updt strings5),7,(first strings5) ++ " EEE " ++ a,[])		
																	else (False,strings,8,buffer,[])				
															else (False,strings,9,buffer,[])						
													else (False,strings,10,buffer,[])								
										else (False,strings,11,buffer,[])									
										
									
localizarIndices :: [String] -> [Int] -> (Bool,[Int],[String])
localizarIndices strings indexes
	|(first strings) == "," = let strings2 = (updt strings) in
								if isInt (first strings2) then localizarIndices (updt strings2) (indexes++[(stringToInt (first strings2))])
								else (False,indexes,strings)
	|(first strings) == ")" = (True,indexes,updt strings)
	|otherwise = (False,indexes,strings)
	
isTypeString :: String -> Bool
isTypeString string
	|string == "String" = True
	|string == "bool" = True
	|string == "int" = True
	|string == "float" = True
	|otherwise = False
	
	
	
	
	
	
										
										
										
																				
																				
												--			if status3 == True then
												--				let (status4,tipo) = obterTipoDeArray in
												--					if status4 == True then
												--						let novoValor = criarNovoArray tipo 
											

--FALTA ADAPTAR OS METODOS PARA O BUFFER E FAZER A IMPRESSAO DO BUFFER NO FINAL										
														
										
--lerStringAteParenteses :: [String] -> String -> (Bool,String,[String])
--letStringAteParenteses [] s = (False,"",[])
--lerStringAteParenteses strings str = if (first strings) == ")" then
---										(True,str,strings)
--									else lerStringSAteParenteses (updt 
									
								



						--let strings2 = (updt lista) in
--						if (first strings2 == ".") then
--						let (status,lista,parametros) = verificarMetodo2 (updt strings2) [] 0 in 
--							if status == True then 
--								verificarParametros classes parametros
		

		


--n = 0: A ultima string foi ponto
--n = 1: a ultima string nao foi ponto								
--verificarMetodo2 :: [String] -> [String] -> Int -> (Bool,[String],[String])
--verificarMetodo2 lista parametros n
--	|first lista == "." && n == 0 = (False,lista,parametros)
--	|first lista == "." && n == 1 = verificarMetodo2 (updt lista) parametros 0
--	|first lista /= "." && n == 1 = (False,lista,parametros)
--	|first lista == "(" && n == 0 = (False,lista,parametros)
--	|first lista == "(" && n == 1 = verificarParametros (updt lista) parametros
--	|otherwise = let (status,rlista) = nome(lista) in
--								if status == True  then verificarMetodo2 (updt lista) ((first lista):parametros)
--								else (False,lista,parametros)
								
--verificarParametros :: [ElementoPilha] -> [Classe] -> [String] -> (Bool,[String],[String])
--verificarParametros pilha classes (metodo:[]) = 
--verificarParametros pilha classes metodo = let (status,elemento) = getElementoDaPilha pilha 

--verificarParametrosNaPilha :: [ElementoPilha] -> [Classe] -> [String] -> Elemento -> (Bool,[String],[String])
--verificarParametrosNaPilha pilha classes lista (nome,Element ClassV x,c,d,e) = let (nomeDaClasse,[var]) = x in
--																	let (status,classe) = getClasse classes nomeDaClasse in
--																		if status == True then
--																			varificarParametrosNaPilha pilha classes (updt lista) 

--	|otherwise = let (status,rlista) = nome(lista) in
--				if status == True then let (a,b,c) = verificarMetodo2 updt lista parametros 1 in
--					(a,b,(stringParaValor(first lista)):c)
--				else let (status,rlista) = numero(lista) in
--					if status == True then let (a,b,c) = verificarMetodo2 updt lista parametros 1 in
--						(a,b,(stringParaValor(first lista)):c)
--				else  let (status,rlista,valor) = verificarMetodo(lista) in
--					if status == True then let (a,b,c) = verificarMetodo2 updt lista parametros 1 in
--						(a,b,(valor):c)
--				else let (status,rlista) = isString(lista) in
--					if status == True then let (a,b,c) = verificarMetodo2 updt lista parametros 1 in
--						(a,b,(stringParaValor(first lista)):c)
--				else (a,b,[])
								
								
								
								
								
						
stringParaValor :: String ->  Valor
stringParaValor [] = Element Null
stringParaValor lista = if (isInt lista) then Element (IntV (stringToInt lista))
						else if (isFloat lista) then Element (FloatV (stringToFloat lista))
						else if isSuelbiString (lista) then Element (StringV (tirarAspasDeString lista))
						else if (lista == "True") then Element (BoolV True)
						else if (lista == "False") then Element (BoolV False)
						else Element Null
						
obterValorDeLiteral :: String -> (Bool,Valor)
obterValorDeLiteral string = 	if string == "True" then (True,(Element (BoolV True)))
								else if string == "False" then (True,(Element (BoolV False)))
								else if isInt string then (True,(Element (IntV (stringToInt (string)))))
								else if isFloat string then (True,(Element (FloatV (stringToFloat (string)))))								
								else if isSuelbiString string then (True,(Element (StringV (tirarAspasDeString string))))
								else (False,(Element (Null)))	
						
						
-- FUNCOES REPETIDAS PARA TESTE
						
executarSentenca1 :: [(String,Indice,PLevel)] -> [(Valor,[Int])] -> ListOfBasics -> (Bool,String,Int)
executarSentenca1 [] operands loB = let (a,b):c = operands in (True,valorParaString a,0)
executarSentenca1 ((a,b,c):d) operands loB = 	let ((opS1,i1),operands2,(str,ndc)) = procurarPrimeiroOperando (a,b,c) operands (Element Null,[b]) in
													let ((opS2,i2),operands3,(str2,ndc2)) = procurarSegundoOperando  (a,b,c) operands2 (str,ndc) in
														let (status,valor) = executarUmaOperacao opS1 opS2 a loB in
														if status == False then (False,valorParaString opS2,1)
														else (executarSentenca1 d (operands3++[(valor,ndc2)]) loB)							
																												   
verificarVariavel1 :: String -> ListOfBasics -> Bool -> Bool
verificarVariavel1 nome ([],classes) st = False
verificarVariavel1 nome ((var,flag):pilha,classes) st
	|flag == 2 = verificarVariavel1 nome (pilha,classes) st
	|flag == 3 = verificarVariavel1 nome (pilha,classes) True
	|flag == 1 && st == False = let (a,b,c,d,e) = var in
							if a == nome then True
							else verificarVariavel1 nome (pilha,classes) st
	|flag == 1 && st == True = let (a,b,c,d,e) = var in
							if a == nome && c == True then True
							else verificarVariavel1 nome (pilha,classes) st
															
																	
-- FUNCOES DE LEITURA E ESCRITA DE DADOS
--Os dados são armazenados em Buffer, e somente executados quando o programa se encerra

printar :: String -> IO String
printar string = 	do
					putStr string
					return string

printarComLinha :: String -> IO String
printarComLinha string = 	do
							putStr (string ++ "\n")
							return string
							
--O Valor em Bool é se True, imprimir new line no final, se não, somente imprimir							
imprimirDadoNoBuffer :: Valor -> Buffer -> Bool -> String							
imprimirDadoNoBuffer v buffer newLine
	|newLine == True = let dado = (valorParaString v) in 
				buffer ++ dado ++ "\n"
	|otherwise = let dado = (valorParaString v) in
				buffer ++ dado
					

-- COMANDOS COM IF					
--------------------------------------------------------
				
isValorBool::Valor -> (Bool,Bool)
isValorBool (Element (BoolV b)) = (True,b)
isValorBool x = (False,False)


-- O primeiro int sempre começa com 0, e o Bool sempre começa com False 					
pularIf::[String] -> ListOfBasics -> Buffer -> Int -> Bool -> Bool -> Bool -> (Bool,[String],ListOfBasics,Buffer)
pularIf [] lista buffer n execElse ehUltimoElse executandoElsif = (False,[],lista,"Chegou Aqui no PularIf")
pularIf strings lista buffer n execElse ehUltimoElse executandoElsif
	|n == 0 && (first strings) == "else" = if ehUltimoElse == True then (False,strings,lista,buffer)
								 else if execElse == True then executarIfSentencas (updt strings) lista buffer True False
								 else pularIf (updt strings) lista buffer n False True False
	|n == 0 && (first strings) == "elsif" = if ehUltimoElse == True then (False,strings,lista,buffer)
											else if execElse == True then if_cond (updt strings) lista buffer True
											else pularIf (updt strings) lista buffer n False False True
	|n == 0 && (first strings) == "endif" = if executandoElsif == True && ehUltimoElse == False then (False,strings,lista, buffer)
											else (True,updt strings,lista,buffer)
	|n >= 0 && (first strings) == "if" = pularIf (updt strings) lista buffer (n + 1) execElse ehUltimoElse executandoElsif
	|n > 0 && (first strings) == "endif" = pularIf (updt strings) lista buffer (n - 1) execElse ehUltimoElse executandoElsif
	|otherwise = pularIf (updt strings) lista buffer n execElse ehUltimoElse executandoElsif
	
	
--	|n == 0 && (first strings) == "else" && execElse == True = executarIfSentencas (updt strings) lista buffer True
--	|n == 0 && (first strings) == "else" && execElse == False && ehUltimoElse == False = pularIf (updt strings) lista buffer False True
--	|n == 0 && ((first strings) == "else" || (first strings) == "elsif") && ehUltimoElse == True = (False,strins,lista,buffer)
--		
--	|n == 0 && (first strings) == "endif" && execElse == False = (True,updt strings,lista,buffer)
--	|n == 0 && (first strings) == "endif" && execElse == True = (False,strins,lista,buffer)
--	
--	|n == 0 && (first strings) == "elsif" && execElse == True = if_cond (updt strings) lista buffer
--	|n == 0 && (first strings) == "elsif" && execElse == False  = pularIf (updt strings) lista buffer
--	
--	|n > 0 && (first strings) == "if" = pularIf (updt strings) lista buffer (n + 1)
--	|n > 0 && (first strings) == "endif" = pularIf (updt strings) lista buffer (n - 1)
--	
--	|n < 0 = (False,[],lista,"Falhou no pularIf n < 0")
--	|(first strings) /= "endif" && (first strings) /= "elsif" && (first strings) /= "if" = pularIf (updt strings) lista buffer n
--	|otherwise = (False,[],lista,"Falhou no pularIf otherwise")					
					
if_cond :: [String] -> ListOfBasics -> Buffer -> Bool -> (Bool,[String],ListOfBasics,Buffer)
if_cond strings listaVelha buffer executandoElsif = let lista = adicionarEscopo2 listaVelha in
										let (status,strings2,valor,buffer2) = verificarOperacao 2 strings lista [] [] 0 0 buffer in
											if status == False then (False,strings,lista,"Falhou no verificar do if_cond")
											else let (status2,v) = isValorBool valor in
												if status2 == False then (False,strings,lista,"Falhou no status2 do if_cond")
												else if v == False then pularIf strings2 lista buffer 0 True False executandoElsif
												else executarIfSentencas strings2 lista buffer2 False executandoElsif
												
-- O ultimo Bool é para verificar se está no último Else
executarIfSentencas :: [String] -> ListOfBasics -> Buffer -> Bool -> Bool -> (Bool,[String],ListOfBasics,Buffer)
executarIfSentencas [] lista buffer ehUltimoElse executandoElsif = (False,[],lista,"Esvaziou Aqui")
executarIfSentencas lexems lista buffer ehUltimoElse executandoElsif
	|(first lexems) == "endif" = let lista2 = limparEscopo2 lista in (True,(updt lexems),lista2,buffer)
	|(first lexems) == "elsif" = 	if ehUltimoElse == False then let lista2 = limparEscopo2 lista in pularIf (updt lexems) lista2 buffer 0 False False True
									else (False,lexems,lista,buffer)
	|(first lexems) == "else"  = 	if ehUltimoElse == True then (False,lexems,lista,buffer)
									else let lista2 = limparEscopo2 lista in pularIf (updt lexems) lista2 buffer 0 False True False	
	-- |(first lexems) == "endif" = let lista2 = limparEscopo2 lista in (True,(updt lexems),lista2,buffer)
	-- |((first lexems) == "elsif") && (ehUltimoElse == False) = let lista2 = limparEscopo2 lista in pularIf (updt lexems) lista2 buffer 0 False False
	-- |((first lexems) == "elsif") && (ehUltimoElse == True) = let lista2 = limparEscopo2 lista in pularIf (updt lexems) lista2 buffer 0 False False
	|otherwise = let bkup_lexems = lexems in
				if first lexems == "def" then 
					let (status,strings2,lista2) = method_dec (updt lexems) lista in
						if status == False then (False,lexems,lista,buffer)
						else executarIfSentencas strings2 lista2 buffer ehUltimoElse executandoElsif
--				else if first lexems == "class" then
--					let (status,lexem) = class_dec (updt lexems) in 
--						if status == False then (False,bkup_lexems)
--						else (True,lexems)				
--				else if first lexems == "module" then
--							let (status,lexem) = module_dec (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
--				else if first lexems == "require" then
--							let (status,lexem) = nome (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
				else if first lexems == "if" then
							let (status,lexems2,lista2,buffer2) = if_cond (updt lexems) lista buffer False in 
								if status == False then (False,bkup_lexems,lista,"Falhou no if do executar IfSentencas")
								else executarIfSentencas lexems2 lista2 buffer2 ehUltimoElse executandoElsif
				else if first lexems == "while" then
							let (status4,lexems4,lista4,buffer4) = while_cond (updt lexems) lista buffer in 
								if status4 == False then (False,bkup_lexems,lista,"Falhou no while do executarWhileSentencas")
								else executarIfSentencas lexems4 lista4 buffer4 ehUltimoElse executandoElsif
--				else if first lexems == "for" then
--							let (status,lexem) = for_cond (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
				else
				let (status,lexems3,lista3,buffer3) = (var_manip lexems lista buffer) in 
								if status == False then (False,bkup_lexems,lista,"Falhou no executar IfSentencas")
								else executarIfSentencas lexems3 lista3 buffer3 ehUltimoElse executandoElsif
					
			
adicionarEscopo2:: ListOfBasics -> ListOfBasics
adicionarEscopo2 (pilha,classes) = ((("",Element Null,False,False,False),2):pilha,classes)

adicionarEscopo3:: ListOfBasics -> ListOfBasics
adicionarEscopo3 (pilha,classes) = ((("",Element Null,False,False,False),3):pilha,classes)

limparEscopo2 :: ListOfBasics -> ListOfBasics
limparEscopo2 ([],classes) = ([],classes)
limparEscopo2 ((var,flag):pilha,classes)
	|flag == 1 = limparEscopo2 (pilha,classes)
	|flag == 2 = (pilha,classes)
	
eliminarEscopo3 :: ListOfBasics -> ListOfBasics
eliminarEscopo3 ([],classes) = ([],classes)
eliminarEscopo3 ((var,flag):pilha,classes)
	|flag == 1 || flag == 2 = limparEscopo2 (pilha,classes)
	|flag == 3 = (pilha,classes)	
	
-- COMANDOS COM WHILE
------------------------------

-- O numero sempre comeca com 0
pularWhile :: [String] -> Int -> (Bool,[String])
pularWhile [] n = (False,[])
pularWhile strings n
	|(first strings) == "endw" = if n == 0 then (True,updt strings)
								 else if n > 0 then pularWhile (updt strings) (n-1)
								 else (False,strings)								 
	|(first strings) == "while" = pularWhile (updt strings) (n+1)
	|otherwise = pularWhile (updt strings) n
	

while_cond :: [String] -> ListOfBasics -> Buffer -> (Bool,[String],ListOfBasics,Buffer)
while_cond strings lista buffer = --let lista2 = adicionarEscopo2 lista in
									let (status,strings2,valor,buffer2) = verificarOperacao 3 strings lista [] [] 0 0 buffer in
										if status == False then (False,strings,lista,"Falhou no verificar do while_cond")
										else let (status2,v) = isValorBool valor in
											if status2 == False then (False,strings,lista,"Falhou no status2 do if_cond")
											else if v == False then let (status3,strings3) = (pularWhile strings2 0) in
													if status3 == False then (False,strings,lista,"Falhou no pula while_cond")
													else (True,strings3,lista,buffer2)												
												else let (status4,strings4,lista4,buffer4) = executarWhileSentencas strings2 lista buffer2 in
													if status4 == True then while_cond strings lista4 buffer4
													else (False,strings,lista,"Falhou na repeticao do while_cond")
														
														
executarWhileSentencas :: [String] -> ListOfBasics -> String -> (Bool,[String],ListOfBasics,Buffer)
executarWhileSentencas [] lista buffer = (False,[],lista,"Esvaziou Aqui no ExecutarWhileSentencas")
executarWhileSentencas lexems lista buffer 
	|(first lexems) == "endw" = let lista2 = limparEscopo2 lista in (True,updt lexems,lista2,buffer)
	|otherwise = let bkup_lexems = lexems in
				if first lexems == "def" then 
					let (status,strings2,lista2) = method_dec (updt lexems) lista in
						if status == False then (False,lexems,lista,buffer)
						else executarWhileSentencas strings2 lista2 buffer
--				else if first lexems == "class" then
--					let (status,lexem) = class_dec (updt lexems) in 
--						if status == False then (False,bkup_lexems)
--						else (True,lexems)				
--				else if first lexems == "module" then
--							let (status,lexem) = module_dec (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
--				else if first lexems == "require" then
--							let (status,lexem) = nome (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
				else if first lexems == "if" then
							let (status,lexems2,lista2,buffer2) = if_cond (updt lexems) lista buffer False in 
								if status == False then (False,bkup_lexems,lista,"Falhou no if do executar IfSentencas")
								else executarWhileSentencas lexems2 lista2 buffer2
				else if first lexems == "while" then
							let (status4,lexems4,lista4,buffer4) = while_cond (updt lexems) lista buffer in 
								if status4 == False then (False,bkup_lexems,lista,"Falhou no while do executarWhileSentencas")
								else executarWhileSentencas lexems4 lista4 buffer4
--				else if first lexems == "for" then
--							let (status,lexem) = for_cond (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
				else
				let (status,lexems3,lista3,buffer3) = (var_manip lexems lista buffer) in 
								if status == False then (False,bkup_lexems,lista,"Falhou no executar IfSentencas")
								else executarWhileSentencas lexems3 lista3 buffer3
-- FUNCOES COM ARRAY
-----------------

isArrayVar :: [String] -> (Bool,[Int],[String])
isArrayVar strings = let (status,strings2) = nome strings in
						if status == False then (False,[],strings)
						else if (first strings2) == "[" then isArrayVar2 (updt strings2) [] 0
						else (False,[],strings)

isArrayVar2 :: [String] -> [Int] -> Int -> (Bool,[Int],[String])
isArrayVar2 strings indexes n
	|n == 0 = if isInt (first strings) then isArrayVar2 (updt strings) (indexes++[(stringToInt (first strings))]) 1
				else (False,indexes,strings)
	|n == 1 = if (first strings) == "]" then isArrayVar2 (updt strings) indexes 2
				else (False,indexes,strings)
	|n == 2 = if (first strings) == "[" then isArrayVar2 (updt strings) indexes 0 else
				if (first strings) == "]" then (False,indexes,strings)
				else (True,indexes,strings)

isTypeArray :: [String] -> (Bool,Int,[String])
isTypeArray strings = let (status,strings2) = nome strings in
						if status == False then (False,0,strings)
						else if (first strings2) == "[" then isTypeArray2 (updt strings2) 1 1				
						else (False,0,strings)
						
isTypeArray2 :: [String] -> Int -> Int -> (Bool,Int,[String])			 
isTypeArray2 strings n qtd
	|n == 0 = if (first strings) == "[" then isTypeArray2 (updt strings) 1 (qtd+1)
			  else if (first strings) == "]" then (False,qtd,strings)
			  else (True,qtd,strings)
	|n == 1 = if (first strings) == "]" then isTypeArray2 (updt strings) 0 qtd
			  else (False,qtd,strings)			  
			  
getValor :: Valor -> [Int] -> (Bool,Valor)
getValor (Element x) [] = (True,Element x)
getValor (Element x) (a:b) = (False,Element Null)
getValor (Array x) (a:[]) = getElementoDoArray x a
getValor (Array x) (a:b) = let (status,valor) = getElementoDoArray x a in
							if status == False then (False,Element Null)
							else getValor valor b
							
--getVariavel :: [String] -> ListOfBascis -> (Bool,Variavel,[String])
--getVariavel strings lista = let (status,dim,strings2) = isArrayVar strings in
--							if status == True then let (status2,(a,valor,b,c,d)) = verificarVariavel (first string) lista False in
--								if status == True then let (status3,valor2) = getValor valor dim in
--									if status == True then 



calcularTamanhoDoValor :: Valor -> Int
calcularTamanhoDoValor (Array val) = calcularTamanhoDoArray val

calcularTamanhoDoArray :: [Valor] -> Int
calcularTamanhoDoArray [] = 0
calcularTamanhoDoArray ((Array x):s) = (calcularTamanhoDoArray x) + (calcularTamanhoDoArray s)
calcularTamanhoDoArray (x:s) = calcularTamanhoDoArray2 s 1
			 		
calcularTamanhoDoArray2 :: [Valor] -> Int -> Int
calcularTamanhoDoArray2 [] n = n
calcularTamanhoDoArray2 (x:s) n = calcularTamanhoDoArray2 s (n+1) 

lerElementosDaPilha::[ElementoPilha]->([String],[Int])
lerElementosDaPilha [] = ([],[])
lerElementosDaPilha (((a,b,c,d,e),f):pilha) = let (ini,fim) = lerElementosDaPilha pilha in (ini ++ [a],fim ++ [calcularTamanhoDoValor b])
		
fazerTesteDeNew::([String],[Int])
fazerTesteDeNew = let (a,b) = substituirVariavel ("j",Array [(Element (IntV 0)),(Element (IntV 0)),(Element (IntV 10)),(Element (IntV 400))],False,False,True) 	([(("j",Array [(Element (IntV 0)),(Element (IntV 10))],False,False,True),1)],[])
					in lerElementosDaPilha a

fazerTesteDeNew2::Int					
fazerTesteDeNew2 = let (a,b,c,d,e) = (obterValorDeElemento ["j",",","int",",","4",",","5",")",";"] ([(("j",(Array [(Array [Element (IntV 0)]),(Array [Element (IntV 1)])]),False,False,True),1)],[]) "")
					in calcularTamanhoDoValor b


fTeste::String -> [Int] -> String
fTeste string n = valorParaString (criarNovoArray string n)

					
criarNovoArray::String -> [Int] -> Valor
criarNovoArray [] n = Element Null
criarNovoArray tipo []
	|tipo == "String" = Element (StringV "")
	|tipo == "bool" = Element (BoolV False)
	|tipo == "float" = Element (FloatV 0)
	|tipo == "int" = Element (IntV 0)
	|otherwise = Element Null	
--criarNovoArray tipo (a:[]) = let valor = criarNovoArray tipo [] in
--								let listaValores = criarArray valor a in
--								(Array (listaValores))
criarNovoArray tipo (a:b) = let valor = criarNovoArray tipo b in
								let listaValores = criarArray valor a in
								(Array (listaValores))

criarArray::Valor -> Int -> [Valor]
criarArray valor n
	|n == 1 = [valor]
	|otherwise = valor:(criarArray valor (n-1))							
							
getElementoDoArrayTeste :: [Valor] -> Int -> (Bool,String)
getElementoDoArrayTeste [] index = (False,"nul")
getElementoDoArrayTeste (a:b) index
	|index == 1 = (True,valorParaString a)
	|otherwise = let (x,j) = getElementoDoArray2 b index (2)
					in (x,valorParaString j)
							
							
							
getElementoDoArray :: [Valor] -> Int -> (Bool,Valor)
getElementoDoArray [] index = (False,Element Null)
getElementoDoArray (a:b) index
	|index == 1 = (True,a)
	|otherwise = getElementoDoArray2 b index (2)
	
substituirElementoDoArrayTeste :: [Valor] -> Int -> Valor -> Int -> (Bool,String)
substituirElementoDoArrayTeste [] n v h  = (False,"fal")
substituirElementoDoArrayTeste (a:b) index nValor h
	| index == 1 = (True,valorParaString nValor)   --(True,(nValor:b))
	|otherwise = let (status,val) = substituirElementoDoArray b (index - 1) nValor in --(True,"legal")
										if status == True then (getElementoDoArrayTeste (a:val) h)
										else (False,"faiou")
					
executarAttribTeste :: String -> Valor -> ListOfBasics -> [Int] -> (Bool,String,Int)
executarAttribTeste nome valor loB indexes =	let (status,var) = (verificarVariavel nome loB False)
													in if status == True then
															let (a,b,c,d,e) = var in
															let (status2,b2) = executarAttrib2 b valor indexes in
															if status2 == False then (False,"null",1) 
															else (True,valorParaString b2,2)									
													   else (False,"nula",3)	
						   
executarAttrib2T :: Valor -> Valor -> [Int] -> (Bool,Valor)	
executarAttrib2T ( Element (IntV recebe)) y (h:t) = (False,y)
executarAttrib2T ( Element (FloatV recebe)) y (h:t) = (False,y)
executarAttrib2T ( Element (StringV recebe)) y (h:t) = (False,y)
executarAttrib2T ( Element (BoolV recebe)) y (h:t) = (False,y)
executarAttrib2T ( Element (FloatV recebe)) y (h:t) = (False,y)
executarAttrib2T x y [] = (True,y)
executarAttrib2T (Array (a:b)) x (h:t) = let (status,valor) = getElementoDoArray (a:b) h in 
														if status == True then
															let (status2,valor2) = (executarAttrib2 valor x t) in
																if status2 == True then
																	let (status3,valor3) = substituirElementoDoArray (a:b) h x in
																		if status3 == True then (True,Array (valor3))
																	else (False,Element (IntV 40))	
																else (False,valor2)
														else (False,valor)
executarAttrib2T (Array (a:b)) x (h:[]) = let (status,valor) = substituirElementoDoArray (a:b) h x in
										if status == True then (True,Array (valor)) else (False,Array (valor))	
	
	
	
substituirElementoDoArray :: [Valor] -> Int -> Valor -> (Bool,[Valor])
substituirElementoDoArray [] n v = (False,[])
substituirElementoDoArray (a:b) index nValor
	| index == 1 = (True,(nValor:b))
	|otherwise = let (status,val) = substituirElementoDoArray b (index - 1) nValor in
					(status,a:val)
	
fx ::(Bool,String)
fx = let (st,val) = substituirElementoDoArray [Element (IntV 0),Element (IntV 4)]  1 (Element (IntV 100))
	in (st,valorArrayParaString val)

	

getElementoDoArray2 :: [Valor] -> Int -> Int -> (Bool,Valor)
getElementoDoArray2 [] indexMax actualIndex = (False,Element Null)
getElementoDoArray2 (a:b) indexMax actualIndex
	|actualIndex < indexMax = getElementoDoArray2 b indexMax (actualIndex + 1)
	|actualIndex == indexMax = (True,a)				  

--Dado um numero n, ele cria um vetor [1,1,...,1] onde 1 aparece n vezes
converterDimensaoEmArray::Int -> [Int]
converterDimensaoEmArray n
	|n == 1 = [1]
	|n > 1 =  1:(converterDimensaoEmArray (n-1))

adicionarNovoArray :: [ElementoPilha] -> String -> String -> [Int] -> [ElementoPilha]
adicionarNovoArray [] tipo nome qtd
	|tipo == "String" = ((nome,(criarNovoArray tipo qtd),False,False,False),1):[]
	|tipo == "bool" = ((nome,(criarNovoArray tipo qtd),False,False,False),1):[]
	|tipo == "float" = ((nome,(criarNovoArray tipo qtd),False,False,False),1):[]
	|tipo == "int" = ((nome,(criarNovoArray tipo qtd),False,False,False),1):[]
	|otherwise = ((nome,(criarNovoArray tipo qtd),False,False,False),1):[]
adicionarNovoArray pilha tipo nome qtd
	|tipo == "String" = ((nome,(criarNovoArray tipo qtd),False,False,False),1):pilha
	|tipo == "bool" = ((nome,(criarNovoArray tipo qtd),False,False,False),1):pilha
	|tipo == "float" = ((nome,(criarNovoArray tipo qtd),False,False,False),1):pilha
	|tipo == "int" = ((nome,(criarNovoArray tipo qtd),False,False,False),1):pilha
	|otherwise = ((nome,(criarNovoArray tipo qtd),False,False,False),1):pilha

-- FUNCOES QUE MEXEM COM METODOS
-----------------------------------------------------

isMetodo:: [String] -> ListOfBasics -> Buffer -> (Bool,ListOfBasics,Valor,[String],Buffer) 
isMetodo strings (pilha,lista) buffer = let (status,strings2) = nome strings in
											if status == True then
												if (first strings2) == "(" then
													let strings3 = updt strings2 in
														let (status2,valores,strings2,buffer2,lista2) = obterParametrosDoMetodo strings3 (pilha,lista) buffer in
															if status2 == True then
																let (a,b,c,d) = executarMetodo (first strings) valores lista2 buffer2
																	in (a,b,c,strings2,d)
															else (False,([],[]),Element Null,[],buffer)
												else (False,([],[]),Element Null,[],buffer)
											 else (False,([],[]),Element Null,[],buffer)											

obterParametrosDoMetodo :: [String] -> ListOfBasics -> Buffer -> (Bool,[Valor],[String],Buffer,ListOfBasics)
obterParametrosDoMetodo strings lista buffer = let (status,valor,strings2,lista2,buffer2) = obterValorDeElemento strings lista buffer in
													if status == True then 
														if (first strings2) == "," then
															let (status2,valores,strings3,buffer2,lista2) = obterParametrosDoMetodo (updt strings2) lista2 buffer2 in
																(status2,valor:valores,strings3,buffer2,lista2)
														else if (first strings2) == ")" then
															(True,[valor],(updt strings2),buffer2,lista2)
														else (False,[],[],buffer2,lista2)
													else (False,[],[],buffer2,lista2)
													
													
													
executarMetodo::String -> [Valor] -> ListOfBasics -> Buffer -> (Bool,ListOfBasics,Valor,Buffer)
executarMetodo nome vars (pilha,lista) buffer = let (status,(nom1,meVars,corpo)) = pegarMetodo nome lista in
											if status == True then
												let (status3,pilha2) = adicionarVariaveis vars meVars pilha in
													if status3 == True then
														let listaNovoEscopo = adicionarEscopo3 (pilha2,lista) in
															let (status2,lista3,valor,buffer2) = executarSentencasDoMetodo corpo listaNovoEscopo buffer in
																if status2 == True then
																	(True,lista3,valor,buffer2)
																else (False,([],[]),Element Null,buffer)
													else (False,([],[]),Element Null,buffer)
											else (False,([],[]),Element Null,buffer)
											
pegarMetodo::String -> [Method_Dec] -> (Bool,Method_Dec)
pegarMetodo nome [] = (False,("",[],[]))
pegarMetodo nome ((met,b,c):metodos)					
	|nome == met = (True,(met,b,c))
	|otherwise = pegarMetodo nome metodos
	
adicionarVariaveis :: [Valor] -> [String] -> [ElementoPilha] -> (Bool,[ElementoPilha])
adicionarVariaveis [] strings pilha = (False,[])
adicionarVariaveis valores [] pilha = (False,[])
adicionarVariaveis (valor:valores) (parametro:outrosPar) pilha = let (status,pilha2) = (adicionarVariaveis valores outrosPar pilha) in
																	(status,(((parametro,valor,False,False,True),1):pilha2)) 




																													
executarSentencasDoMetodo :: [String] -> ListOfBasics -> Buffer -> (Bool,ListOfBasics,Valor,Buffer)
executarSentencasDoMetodo [] lista buffer = (False,([],[]),Element Null,buffer)
executarSentencasDoMetodo strings lista buffer
	|(first strings) == "endmet" = (True,eliminarEscopo3 lista,Element Null,buffer)
	|(first strings) == "return" = let (status,valor,strings2,lista2,buffer2) = obterValorDeElemento (updt strings) lista buffer in
										if status == True then (True,eliminarEscopo3 lista2,valor,buffer2)
										else (False,([],[]),Element Null,buffer)							
	|otherwise = let bkup_lexems = strings in
				if first strings == "def" then 
					let (status,strings2,lista2) = method_dec (updt strings) lista in
						if status == False then (False,([],[]),Element Null,buffer)
						else executarSentencasDoMetodo strings2 lista2 buffer
--				else if first lexems == "class" then
--					let (status,lexem) = class_dec (updt lexems) in 
--						if status == False then (False,bkup_lexems)
--						else (True,lexems)				
--				else if first lexems == "module" then
--							let (status,lexem) = module_dec (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
--				else if first lexems == "require" then
--							let (status,lexem) = nome (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
				else if first strings == "if" then
							let (status,lexems2,lista2,buffer2) = if_cond (updt strings) lista buffer False in 
								if status == False then (False,lista2,Element Null,"Falhou no if do executar IfSentencas")
								else executarSentencasDoMetodo lexems2 lista2 buffer2
				else if first strings == "while" then
							let (status4,lexems4,lista4,buffer4) = while_cond (updt strings) lista buffer in 
								if status4 == False then (False,lista4,Element Null,"Falhou no while do executarWhileSentencas")
								else executarSentencasDoMetodo lexems4 lista4 buffer4
--				else if first lexems == "for" then
--							let (status,lexem) = for_cond (updt lexems) in 
--								if status == False then (False,bkup_lexems)
--								else (True,lexems)
				else
				let (status,lexems3,lista3,buffer3) = (var_manip strings lista buffer) in 
								if status == False then (False,lista3,Element Null,"Falhou no executar IfSentencas")
								else executarSentencasDoMetodo lexems3 lista3 buffer3
										





method_dec::[String] -> ListOfBasics -> (Bool,[String],ListOfBasics)
method_dec strings lista = let (jaExiste,strings2) = nomeDeMetodoJaExiste strings lista in
						if jaExiste == False then
							if (first strings2) == "(" then
								let (status2,listaDeVariaveis,strings3) = armazenarVarsDeMetodo (updt strings2) in
									if status2 == True then
										let (status3,corpoDoMetodo,strings4) = armazenarCodigoDoMetodo strings3 0 in
											if status3 == True then
												let lista2 = adicionarMetodo ((first strings),listaDeVariaveis,corpoDoMetodo) lista in
													(True,strings4,lista2)
											else (False,[],([],[]))
									else (False,[],([],[]))			
							else (False,[],([],[]))			
						else (False,[],([],[]))
						
-- O int deve sempre começar com 0						
armazenarCodigoDoMetodo :: [String] -> Int -> (Bool,[String],[String])
armazenarCodigoDoMetodo [] n = (False,[],[])
armazenarCodigoDoMetodo strings n
	|(first strings) == "endmet" && n == 0 = (True,[first strings],updt strings)
	|(first strings) == "endmet" && n > 0 = let (status,corpoParcial,strings2) = armazenarCodigoDoMetodo (updt strings) (n - 1) in 
												(status,(first strings):corpoParcial,strings2)	
	|(first strings) == "def" =  let (status,corpoParcial,strings2) = armazenarCodigoDoMetodo (updt strings) (n + 1) in
									(status,(first strings):corpoParcial,strings2)	
	|otherwise =  let (status,corpoParcial,strings2) = armazenarCodigoDoMetodo (updt strings) n in
					(status,(first strings):corpoParcial,strings2)									
					
adicionarMetodo :: Method_Dec -> ListOfBasics -> ListOfBasics
adicionarMetodo mdec (pilha,lista) = (pilha,mdec:lista)						
						
armazenarVarsDeMetodo::[String] -> (Bool,[String],[String])
armazenarVarsDeMetodo [] = (False,[],[])
armazenarVarsDeMetodo strings = let (status,strings2) = nome strings in
									if status == True then
										if (first strings2) == "," then
											let (status2,listaTemporaria,strings3) = armazenarVarsDeMetodo (updt strings2) in
												(status2,(first strings):listaTemporaria,strings3)
										else if (first strings2) == ")" then (True,[first strings],updt strings2)
										else (False,[],[])
									else (False,[],[])			
						
nomeDeMetodoJaExiste::[String] -> ListOfBasics -> (Bool,[String])
nomeDeMetodoJaExiste [] (pilha,(a,b,c):methods) = (True,[])
nomeDeMetodoJaExiste strings (pilha,[]) = (False,updt strings)
nomeDeMetodoJaExiste strings (pilha,(a,b,c):methods) = if (first strings) == a then (True,[])
														else nomeDeMetodoJaExiste strings (pilha,methods)
															





	
	
	
	
	
	